package org.tlang.context;

import org.tlang.exception.EvalException;

import java.util.Arrays;

public class ValueTable {
    protected Object[] values;
    protected final ValueTable outer;
    private final String tag;

    public ValueTable(int initSize, String tag) {
        this(initSize, null, tag);
    }

    public ValueTable(int initSize, ValueTable outer, String tag) {
        this.values = new Object[initSize];
        this.outer = outer;
        this.tag = tag;
    }

    public ValueTable outer() {
        return outer;
    }

    public Object get(int nest, int index) {
        if (nest == 0) {
            verifyIndex(index);
            return values[index];
        } else {
            assertOuterNotNull();
            return outer.get(nest - 1, index);
        }
    }

    public void add(int index, Object value) {
        if (index >= values.length) {
            int newLength = values.length << 1;
            if (index >= newLength) {
                newLength = index + 1;
            }
            values = Arrays.copyOf(values, newLength); // 扩容values
        }

        values[index] = value;
    }

    public void update(int nest, int index, Object value) {
        if (nest == 0) {
            verifyIndex(index);
            values[index] = value;
        } else {
            assertOuterNotNull();
            outer.update(nest - 1, index, value);
        }
    }

    private void verifyIndex(int index) {
        if (index >= values.length || index < 0) {
            throw new EvalException("index out of range");
        }
    }

    private void assertOuterNotNull() {
        if (outer == null) {
            throw new EvalException("no outer context");
        }
    }

    @Override
    public String toString() {
        return tag;
    }
}
